#include "../head/client.h"
#include "../head/md5.h"

// 处理长命令，线程的启动函数

// puts
void *upload(void *arg)
{
	shareRes_t *pshareRes = (shareRes_t *)arg;
	char order[1024] = {0};
	char path[1024] = {0};
	char token[1024] = {0};
	char username[1024] = {0};
	strcpy(order, pshareRes->order);
	strcpy(path, pshareRes->path);
	strcpy(token, pshareRes->token);
	strcpy(username, pshareRes->username);

	int file_fd = open(path, O_RDONLY);
	ERROR_CHECK(file_fd, -1, "open");

	char md5_str[MD5_STR_LEN + 1];
	compute_file_md5(file_fd, md5_str);
	lseek(file_fd, 0, SEEK_SET);

	// 文件名字需要从path中截取
	char filename[1024] = {0};
	int i;
	for (i = strlen(path) - 1; i > 0; i--)
	{
		if (path[i] == '/') // 路径从后往前第一个'/'
			break;
	}
	if (i)
		strcpy(filename, (path + i + 1));
	else // i==0,意味path存的就是个文件名
		strcpy(filename, path);
	printf("需要上传文件的名字：%s\n", filename);

	// 用于长命令通信的socket_fd
	/* int new_fd = socket(AF_INET, SOCK_STREAM, 0);
	NETDISK_LOG_ERR(new_fd, -1, "long socket");
	int ret = connect(new_fd, (struct sockaddr *)&pshareRes->serverAddr, sizeof(pshareRes->serverAddr));
	NETDISK_LOG_ERR(ret, -1, "long connect"); */

	// 从配置文件中加载服务器ip
	char ip[100];
	bzero(ip, sizeof(ip));
	getparameter("ip", ip); // getparameter.c
	// printf("ip: %s\n", ip);
	// 从配置文件中加载服务器端口
	char port[100];
	bzero(port, sizeof(port));
	getparameter("port", port); // getparameter.c
	// printf("port: %s\n", port);
	int new_fd = socket(AF_INET, SOCK_STREAM, 0);
	ERROR_CHECK(new_fd, -1, "socket");

	struct sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(atoi(port));
	serverAddr.sin_addr.s_addr = inet_addr(ip);
	int res_conn = connect(new_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	ERROR_CHECK(res_conn, -1, "connect");

	train_t train;
	bzero(&train, sizeof(train));
	// 通知服务器此时是长命令
	train.length = strlen("long");
	strcpy(train.data, "long");
	send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

	// 发送用户名和token验证身份
	// printf("username: %s\n", username);
	send_str(new_fd, username);
	// printf("token: %s\n", token);
	send_str(new_fd, token);
	/* bzero(&train, sizeof(train));
	train.length = strlen(username);
	strcpy(train.data, username);
	printf("train.length: %d\n", train.length);
	// send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
	send(new_fd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
	send(new_fd, train.data, train.length, MSG_NOSIGNAL);
	sleep(100);
	bzero(&train, sizeof(train));
	train.length = strlen(token);
	strcpy(train.data, token);
	send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
	 */
	// 接收服务器返回的验证结果
	bzero(&train, sizeof(train));
	recv(new_fd, &train.length, sizeof(train.length), MSG_WAITALL);
	recv(new_fd, train.data, train.length, MSG_WAITALL);
	printf("%s\n", train.data);
	if (!strcmp(train.data, "verify_fail"))
	{
		NETDISK_LOG_ERR("error token");
		printf("error token!\n");
		close(new_fd);
		return (void *)-1;
	}

	// 发送puts指令、文件名、md5加密hash给服务器
	send_str(new_fd, order);
	send_str(new_fd, username);
	send_str(new_fd, filename);
	send_str(new_fd, md5_str);

	// 接收服务器的确认信息，判断要上传的文件是否存在
	bzero(&train, sizeof(train));
	recv(new_fd, &train.length, sizeof(train.length), MSG_WAITALL);
	recv(new_fd, train.data, train.length, MSG_WAITALL);
	if (!strcmp(train.data, "topspeed")) // 服务器中已经存在该文件了
	{
		NETDISK_LOG_INFO_2(new_fd, "极速上传成功", username);
		printf("极速上传成功！\n");
		close(file_fd);
		return 0;
	}
	else if (!strcmp(train.data, "error"))
	{
		NETDISK_LOG_ERR("服务器故障");
		printf("服务器故障！\n");
		close(file_fd);
		return 0;
	}

	printf("上传中...\n");
	send_file(new_fd, file_fd);
	printf("上传成功！\n");
	NETDISK_LOG_INFO_2(new_fd, "上传文件成功", username);

	close(new_fd);
	close(file_fd);

	return NULL;
}

// gets
void *download(void *arg)
{
	shareRes_t *pshareRes = (shareRes_t *)arg;
	char order[1024] = {0};
	char path[1024] = {0};
	char token[1024] = {0};
	char username[1024] = {0};
	strcpy(order, pshareRes->order);
	strcpy(path, pshareRes->path);
	strcpy(token, pshareRes->token);
	strcpy(username, pshareRes->username);

	// 用于长命令通信的socket_fd
	/* int new_fd = socket(AF_INET, SOCK_STREAM, 0);
	NETDISK_LOG_ERR(new_fd, -1, "long socket");
	int ret = connect(new_fd, (struct sockaddr *)&pshareRes->serverAddr, sizeof(pshareRes->serverAddr));
	NETDISK_LOG_ERR(ret, -1, "long connect"); */
	// 从配置文件中加载服务器ip
	char ip[100];
	bzero(ip, sizeof(ip));
	getparameter("ip", ip); // getparameter.c
	// printf("ip: %s\n", ip);
	// 从配置文件中加载服务器端口
	char port[100];
	bzero(port, sizeof(port));
	getparameter("port", port); // getparameter.c
	// printf("port: %s\n", port);
	int new_fd = socket(AF_INET, SOCK_STREAM, 0);
	ERROR_CHECK(new_fd, -1, "socket");
	struct sockaddr_in serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(atoi(port));
	serverAddr.sin_addr.s_addr = inet_addr(ip);
	int res_conn = connect(new_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	ERROR_CHECK(res_conn, -1, "connect");

	train_t train;
	bzero(&train, sizeof(train));
	// 通知服务器此时是长命令
	train.length = strlen("long");
	strcpy(train.data, "long");
	send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

	// 发送用户名和token验证身份
	bzero(&train, sizeof(train));
	train.length = strlen(username);
	strcpy(train.data, username);
	send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
	bzero(&train, sizeof(train));
	train.length = strlen(token);
	strcpy(train.data, token);
	send(new_fd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
	/* // 接收服务器返回的验证结果
	bzero(&train, sizeof(train));
	recv(new_fd, &train.length, sizeof(train.length), MSG_WAITALL);
	if (train.length == 0)
	{
		NETDISK_LOG_ERR("error token");
		printf("error token!\n");
		close(new_fd);
		return (void *)-1;
	} */
	// 接收服务器返回的验证结果
	bzero(&train, sizeof(train));
	recv(new_fd, &train.length, sizeof(train.length), MSG_WAITALL);
	recv(new_fd, train.data, train.length, MSG_WAITALL);
	printf("%s\n", train.data);
	if (!strcmp(train.data, "verify_fail"))
	{
		NETDISK_LOG_ERR("error token");
		printf("error token!\n");
		close(new_fd);
		return (void *)-1;
	}

	// 发送gets命令、要下载的路径名给服务器
	send_str(new_fd, order);
	send_str(new_fd, username);
	send_str(new_fd, path);

	// 接收服务器的确认信息，判断要下载的文件是否存在
	bzero(&train, sizeof(train));
	recv(new_fd, &train.length, sizeof(train.length), MSG_WAITALL);
	// printf("%d\n", train.length);
	recv(new_fd, train.data, train.length, MSG_WAITALL);
	// printf("%s\n", train.data);
	if (!strcmp(train.data, "no")) // 服务器中不存在该文件
	{
		NETDISK_LOG_ERR("文件不存在");
		printf("文件不存在!\n");
		return (void *)-1;
	}

	// 文件名字需要从path中截取
	char filename[1024] = {0};
	int i;
	for (i = strlen(path) - 1; i > 0; i--)
	{
		if (path[i] == '/') // 路径从后往前第一个'/'
			break;
	}
	if (i)
		strcpy(filename, (path + i + 1));
	else // i==0,意味path存的就是个文件名
		strcpy(filename, path);
	printf("需要下载文件的名字：%s\n", filename);

	// 断点下载
	bzero(&train, sizeof(train));
	int acs_ret = access(filename, F_OK);
	int file_fd;
	if (acs_ret == 0) // 需要下载的文件已经存在
	{
		file_fd = open(filename, O_RDWR | O_APPEND);
		ERROR_CHECK(file_fd, -1, "open");
		struct stat statbuf;
		fstat(file_fd, &statbuf);

		// 告诉服务器目前已存在的文件的大小
		send(new_fd, &statbuf.st_size, sizeof(off_t), MSG_NOSIGNAL);
	}
	else // 新建文件到./client/source/目录下
	{
		file_fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0666);
		ERROR_CHECK(file_fd, -1, "open");
		// 告诉服务器目前已存在的文件的大小
		off_t file_size = 0;
		send(new_fd, &file_size, sizeof(off_t), MSG_NOSIGNAL);
	}

	printf("下载中...\n");
	recv_file(new_fd, file_fd);
	printf("下载成功！\n");
	NETDISK_LOG_INFO_2(new_fd, "下载文件成功", username);

	close(new_fd);
	close(file_fd);

	return NULL;
}
